| Jordan Taylor | 7ae3824 | 2020-02-13 01:56:46 | [diff] [blame] | 1 | <!DOCTYPE html> |
| 2 | <meta charset=utf-8> |
| 3 | <title>Setting the playback rate of an animation that is using a ScrollTimeline</title> |
| 4 | <link rel="help" href="https://drafts.csswg.org/web-animations/#setting-the-playback-rate-of-an-animation"> |
| 5 | <script src="/resources/testharness.js"></script> |
| 6 | <script src="/resources/testharnessreport.js"></script> |
| 7 | <script src="/web-animations/testcommon.js"></script> |
| 8 | <script src="testcommon.js"></script> |
| 9 | <style> |
| 10 | .scroller { |
| 11 | overflow: auto; |
| 12 | height: 100px; |
| 13 | width: 100px; |
| 14 | } |
| 15 | .contents { |
| 16 | height: 1000px; |
| 17 | width: 100%; |
| 18 | } |
| 19 | </style> |
| 20 | <body> |
| 21 | <script> |
| 22 | 'use strict'; |
| 23 | promise_test(async t => { |
| 24 | const animation = createScrollLinkedAnimation(t); |
| 25 | const scroller = animation.timeline.scrollSource; |
| 26 | // this forces a layout which results in an active timeline |
| 27 | scroller.scrollTop = 0; |
| 28 | |
| 29 | animation.playbackRate = 0.5; |
| 30 | animation.play(); |
| 31 | |
| 32 | assert_equals(animation.currentTime, 0, |
| 33 | 'Zero current time is not affected by playbackRate change.'); |
| 34 | }, 'Zero current time is not affected by playbackRate set while the ' + |
| 35 | 'animation is in idle state.'); |
| 36 | |
| 37 | promise_test(async t => { |
| 38 | const animation = createScrollLinkedAnimation(t); |
| 39 | const scroller = animation.timeline.scrollSource; |
| 40 | // this forces a layout which results in an active timeline |
| 41 | scroller.scrollTop = 0; |
| 42 | |
| 43 | animation.play(); |
| 44 | animation.playbackRate = 0.5; |
| 45 | |
| 46 | assert_equals(animation.currentTime, 0, |
| 47 | 'Zero current time is not affected by playbackRate change.'); |
| 48 | }, 'Zero current time is not affected by playbackRate set while the ' + |
| 49 | 'animation is in play-pending state.'); |
| 50 | |
| 51 | promise_test(async t => { |
| 52 | const animation = createScrollLinkedAnimation(t); |
| 53 | const scroller = animation.timeline.scrollSource; |
| 54 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 55 | const timeRange = animation.timeline.timeRange; |
| 56 | scroller.scrollTop = 0.2 * maxScroll; |
| 57 | |
| 58 | animation.playbackRate = 0.5; |
| 59 | animation.play(); |
| 60 | await animation.ready; |
| 61 | assert_equals(animation.currentTime, 0.2 * timeRange * 0.5, |
| 62 | 'Initial current time is scaled by playbackRate change.'); |
| 63 | }, 'Initial current time is scaled by playbackRate set while ' + |
| 64 | 'scroll-linked animation is in running state.'); |
| 65 | |
| 66 | promise_test(async t => { |
| 67 | const animation = createScrollLinkedAnimation(t); |
| 68 | const scroller = animation.timeline.scrollSource; |
| 69 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 70 | const timeRange = animation.timeline.timeRange; |
| 71 | const playbackRate = 2; |
| 72 | |
| 73 | scroller.scrollTop = 0.2 * maxScroll; |
| 74 | |
| 75 | animation.play(); |
| 76 | await animation.ready; |
| 77 | // Set playback rate while the animation is playing. |
| 78 | animation.playbackRate = playbackRate; |
| 79 | assert_times_equal(animation.currentTime, 0.2 * timeRange, |
| 80 | 'The current time should stay unaffected by setting playback rate.'); |
| 81 | }, 'The current time is not affected by playbackRate set while the ' + |
| 82 | 'scroll-linked animation is in play state.'); |
| 83 | |
| 84 | promise_test(async t => { |
| 85 | const animation = createScrollLinkedAnimation(t); |
| 86 | const scroller = animation.timeline.scrollSource; |
| 87 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 88 | const timeRange = animation.timeline.timeRange; |
| 89 | |
| 90 | // Set playback rate while the animation is in 'idle' state. |
| 91 | animation.playbackRate = 2; |
| 92 | animation.play(); |
| 93 | await animation.ready; |
| 94 | scroller.scrollTop = 0.2 * maxScroll; |
| 95 | |
| 96 | assert_times_equal(animation.currentTime, 0.2 * timeRange * 2, |
| 97 | 'The current time should increase two times faster than timeline time.'); |
| 98 | }, 'The playback rate set before scroll-linked animation started playing ' + |
| 99 | 'affects the rate of progress of the current time'); |
| 100 | |
| 101 | promise_test(async t => { |
| 102 | const animation = createScrollLinkedAnimation(t); |
| 103 | const scroller = animation.timeline.scrollSource; |
| 104 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 105 | animation.play(); |
| 106 | |
| 107 | await animation.ready; |
| 108 | |
| 109 | animation.playbackRate = 2; |
| 110 | scroller.scrollTop = 0.25 * maxScroll; |
| 111 | |
| 112 | assert_times_equal( |
| 113 | animation.currentTime, |
| 114 | animation.timeline.currentTime * animation.playbackRate, |
| 115 | 'The current time should increase two times faster than timeline time' |
| 116 | ); |
| 117 | }, 'The playback rate affects the rate of progress of the current time' + |
| 118 | ' when scrolling'); |
| 119 | |
| 120 | test(t => { |
| 121 | const animation = createScrollLinkedAnimation(t); |
| 122 | const scroller = animation.timeline.scrollSource; |
| 123 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 124 | scroller.scrollTop = 0.25 * maxScroll; |
| 125 | animation.play(); |
| 126 | |
| 127 | animation.playbackRate = 2; |
| 128 | |
| 129 | assert_equals(animation.playState, "running"); |
| 130 | assert_true(animation.pending); |
| 131 | assert_times_equal(animation.currentTime, animation.timeline.currentTime); |
| 132 | }, 'Setting the playback rate while play-pending preserves the current time' + |
| 133 | ' from scrollTimeline.'); |
| 134 | |
| 135 | test(t => { |
| 136 | const animation = createScrollLinkedAnimation(t); |
| 137 | animation.play(); |
| 138 | animation.currentTime = 250; |
| 139 | animation.playbackRate = 2; |
| 140 | |
| 141 | assert_equals(animation.playState, "running"); |
| 142 | assert_true(animation.pending); |
| 143 | assert_times_equal(animation.currentTime, 250); |
| 144 | }, 'Setting the playback rate while play-pending preserves the set current' + |
| 145 | ' time.'); |
| 146 | |
| 147 | promise_test(async t => { |
| 148 | const animation = createScrollLinkedAnimation(t); |
| 149 | const scroller = animation.timeline.scrollSource; |
| 150 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 151 | scroller.scrollTop = 0.25 * maxScroll; |
| 152 | animation.play(); |
| 153 | |
| 154 | await animation.ready; |
| 155 | animation.playbackRate = 2; |
| 156 | |
| 157 | assert_times_equal(animation.currentTime, animation.timeline.currentTime); |
| 158 | }, 'Setting the playback rate while playing preserves the current time' + |
| 159 | ' from scrollTimeline.'); |
| 160 | |
| 161 | promise_test(async t => { |
| 162 | const animation = createScrollLinkedAnimation(t); |
| 163 | |
| 164 | /* Wait for animation frame is here for now to avoid a renderer crash |
| 165 | caused by crbug.com/1042924. Once that is fixed, these can be removed */ |
| 166 | await waitForAnimationFrames(2); |
| 167 | |
| 168 | animation.play(); |
| 169 | |
| 170 | animation.currentTime = 250; |
| 171 | await animation.ready; |
| 172 | animation.playbackRate = 2; |
| 173 | |
| 174 | assert_times_equal(animation.currentTime, 250); |
| 175 | }, 'Setting the playback rate while playing preserves the set current time.'); |
| 176 | |
| 177 | promise_test(async t => { |
| 178 | const animation = createScrollLinkedAnimation(t); |
| 179 | const scroller = animation.timeline.scrollSource; |
| 180 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 181 | const range = animation.timeline.timeRange; |
| 182 | animation.playbackRate = -1; |
| 183 | scroller.scrollTop = 0.3 * maxScroll; |
| 184 | animation.play(); |
| 185 | |
| 186 | await animation.ready; |
| 187 | const expectedCurrentTime = range - animation.timeline.currentTime; |
| 188 | assert_times_equal(animation.currentTime, expectedCurrentTime); |
| 189 | }, 'Negative initial playback rate should correctly modify initial current' + |
| 190 | ' time.'); |
| 191 | |
| 192 | promise_test(async t => { |
| 193 | const animation = createScrollLinkedAnimation(t); |
| 194 | const scroller = animation.timeline.scrollSource; |
| 195 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 196 | scroller.scrollTop = 0.5 * maxScroll; |
| 197 | animation.play(); |
| 198 | |
| 199 | await animation.ready; |
| 200 | const startingTimelineTime = animation.timeline.currentTime; |
| 201 | const startingCurrentTime = animation.currentTime; |
| 202 | assert_times_equal(startingCurrentTime, startingTimelineTime); |
| 203 | |
| 204 | animation.playbackRate = -1; |
| 205 | |
| 206 | scroller.scrollTop = 0.8 * maxScroll; |
| 207 | // -300 = 500 - 800 |
| 208 | let timelineDiff = startingTimelineTime - animation.timeline.currentTime; |
| 209 | // 200 = 500 + (-300) |
| 210 | let expected = startingCurrentTime + timelineDiff; |
| 211 | assert_times_equal(animation.currentTime, expected); |
| 212 | |
| 213 | scroller.scrollTop = 0.2 * maxScroll; |
| 214 | // 300 = 500 - 200 |
| 215 | timelineDiff = startingTimelineTime - animation.timeline.currentTime; |
| 216 | // 800 = 500 + 300 |
| 217 | expected = startingCurrentTime + timelineDiff; |
| 218 | assert_times_equal(animation.currentTime, expected); |
| 219 | }, 'Reversing the playback rate while playing correctly impacts current' + |
| 220 | ' time during future scrolls'); |
| 221 | |
| 222 | promise_test(async t => { |
| 223 | const animation = createScrollLinkedAnimation(t); |
| 224 | const scroller = animation.timeline.scrollSource; |
| 225 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 226 | const range = animation.timeline.timeRange; |
| 227 | animation.playbackRate = 0; |
| 228 | scroller.scrollTop = 0.3 * maxScroll; |
| 229 | animation.play(); |
| 230 | |
| 231 | await animation.ready; |
| 232 | assert_times_equal(animation.currentTime, 0); |
| 233 | }, 'Zero initial playback rate should correctly modify initial current' + |
| 234 | ' time.'); |
| 235 | |
| 236 | promise_test(async t => { |
| 237 | const animation = createScrollLinkedAnimation(t); |
| 238 | const scroller = animation.timeline.scrollSource; |
| 239 | const maxScroll = scroller.scrollHeight - scroller.clientHeight; |
| 240 | scroller.scrollTop = 0.2 * maxScroll; |
| 241 | animation.play(); |
| 242 | |
| 243 | await animation.ready; |
| 244 | assert_times_equal(animation.currentTime, 200); |
| 245 | animation.playbackRate = 0; |
| 246 | scroller.scrollTop = 0.5 * maxScroll; |
| 247 | |
| 248 | // Ensure that current time does not change. |
| 249 | assert_time_equals_literal(animation.timeline.currentTime, 500); |
| 250 | assert_time_equals_literal(animation.currentTime, 200); |
| 251 | }, 'Setting a zero playback rate while running preserves the current time'); |
| 252 | </script> |
| 253 | </body> |